package com.admin.system.security.service;

import com.admin.model.pojo.Menu;
import com.admin.model.pojo.Role;
import com.admin.model.pojo.User;
import com.admin.system.dao.RoleDao;
import com.admin.system.dao.UserDao;
import com.admin.system.service.mapstruct.UserMapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author caixiaofeng
 * @version 1.0
 * @Description: <<>>
 * @company cxf
 * @create 2021-01-28 19:51
 */
@Component
public class UserDetailsServiceImpl implements UserDetailsService {
    @Resource
    private UserDao userDao;
    @Resource
    private RoleDao roleDao;
    @Resource
    private UserMapper userMapper;
    //缓存用户信息
    private static Map<String, UserDetailsImpl> userCache = new ConcurrentHashMap<>();

    // @Cacheable(value = "user",key = "'users:'+#p0")
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if (userCache.containsKey(username)) {
            UserDetailsImpl userDetails = userCache.get(username);
            return userDetails;
        }
        //查询用户信息
        User user = new LambdaQueryChainWrapper<>(userDao).eq(User::getUsername, username).one();
        Assert.notNull(user, "账户或密码错误");
        UserDetailsImpl userDetailsImpl = new UserDetailsImpl();
        userDetailsImpl.setUser(userMapper.toDto(user));

        //取出角色权限
        List<Role> roles = user.getRoles();
        Set<SimpleGrantedAuthority> roleAuths = roles.stream().
                filter(role -> !role.getName().isEmpty())
                .map(role -> "ROLE_" + role.getName())
                .collect(Collectors.toSet())
                .stream().map(SimpleGrantedAuthority::new)
                .collect(Collectors.toSet());
        List<Long> roleIds = roles.stream().map(Role::getId).collect(Collectors.toList());

        //取出菜单权限
        List<Menu> menus = roleDao.queryMenuByRoleIdsAndTypeNot(roleIds, 0);
        Set<SimpleGrantedAuthority> menuAuths = menus.stream()
                .filter(menu -> !StringUtils.isEmpty(menu.getPermission()))
                .map(Menu::getPermission).collect(Collectors.toSet())
                .stream().map(SimpleGrantedAuthority::new).collect(Collectors.toSet());

        //菜单权限与角色权限合并
        Set<GrantedAuthority> authorities = Stream.concat(menuAuths.stream(), roleAuths.stream()).collect(Collectors.toSet());
        userDetailsImpl.setAuthorities(authorities);

        //放入缓存
        userCache.put(userDetailsImpl.getUsername(), userDetailsImpl);
        return userDetailsImpl;
    }

    /**
     * 删除用户缓存
     * @param username
     */
    public static void clearCacheUser(String username) {
        userCache.remove(username);
    }

    /**
     * 删除所有用户缓存
     */
    public static void clearCachUserAll(){
        userCache.clear();
    }
}
